﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Text.RegularExpressions;

namespace API.WindowsLive.SkyDrive
{
    class Scheduler
    {
        DateTime startTime, endTime;
        Boolean schedulerOn, loopSchedule;
        Thread thread;

        public Scheduler(DateTime startDate, DateTime endDate, Thread thread, Boolean schedulerOn, Boolean loopSchedule )
        {
            this.startTime = startDate;
            this.endTime = endDate;

            if (startTime > endTime)
                endTime = endTime.AddDays(1);

            this.schedulerOn = schedulerOn;
            this.loopSchedule = loopSchedule;
            this.thread = thread;
        }

        public Scheduler(String startString, String endString, Thread thread, Boolean schedulerOn, Boolean loopSchedule)
        {
            startTime = (isTimeValid(startString)) ? createTime(startString) : DateTime.Now;
            endTime = (isTimeValid(endString)) ? createTime(endString) : startTime;

            if (startTime > endTime)
                endTime = endTime.AddDays(1);

            this.thread = thread;
            this.schedulerOn = schedulerOn;
            this.loopSchedule = loopSchedule;
        }

        public void launchSchedule()
        {
            if (schedulerOn)
            {
                do
                {
                    if (startTime > DateTime.Now)
                    {
                        RaiseWait(this, new EventArgs());
                        int waitFor = (int)((startTime.Ticks - DateTime.Now.Ticks) / TimeSpan.TicksPerMillisecond);
                        Thread.Sleep(waitFor);
                    }

                    thread.Start();
                    RaiseStart(this, new EventArgs());

                    int waitTimeInMilliseconds = (endTime > DateTime.Now) ? (int)((endTime.Ticks - DateTime.Now.Ticks) / TimeSpan.TicksPerMillisecond) : 0;

                    thread.Join(waitTimeInMilliseconds);

                    if (thread.IsAlive)
                    {
                        thread.Abort();
                    }

                    RaiseEnd(this, new EventArgs());

                    startTime = startTime.AddDays(1);
                    endTime = endTime.AddDays(1);
                } while (loopSchedule);
            }
            else
            {
                thread.Start();
                RaiseStart(this, new EventArgs());
                thread.Join();
            }
        }

        static Boolean isTimeValid(String timeStrings)
        {
            Regex regularExp = new Regex(@"^((2[0-3])|([0-1]\d))(:[0-5]\d)(:[0-5]\d)?$");
            return (timeStrings == null) ? false : regularExp.IsMatch(timeStrings);
        }

        static DateTime createTime(String timeString)
        {
            DateTime newTime;
            DateTime now = DateTime.Now;

            if (timeString.Length < 8)
            {
                newTime = new DateTime(now.Year, now.Month, now.Day, Int16.Parse(timeString.Substring(0, 2)), Int16.Parse(timeString.Substring(3, 2)), 0);
            }
            else
            {
                newTime = new DateTime(now.Year, now.Month, now.Day, Int16.Parse(timeString.Substring(0, 2)), Int16.Parse(timeString.Substring(3, 2)), Int16.Parse(timeString.Substring(6, 2)));
            }

            return newTime;
        }

        # region delegates and events
        
        public delegate void StartHandler(object sender, EventArgs e);
        public event StartHandler RaiseStart;

        public delegate void EndHandler(object sender, EventArgs e);
        public event EndHandler RaiseEnd;

        public delegate void WaitHandler(object sender, EventArgs e);
        public event WaitHandler RaiseWait;
        
        # endregion

    }
}

